/*
 * SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

use anyhow::Result;

use crate::cli::ZipArgs;
use crate::error::ZipError;

use crate::utils::common::{
    copy_local_file_to_zip, filter_filesystem_files, init_run_state, prepare_files_map,
    should_update_file,
};

pub fn execute(args: &ZipArgs) -> Result<()> {
    log::info!("Starting dif operation...");
    let mut run_state = init_run_state(args)?;

    // 输入的文件列表
    let file_selects = prepare_files_map(args, &args.command, run_state.zip_file_tmp.as_ref())?;
    let files_map: std::collections::BTreeMap<String, std::path::PathBuf> =
        filter_filesystem_files(&file_selects, args);

    if files_map.is_empty() {
        return Err(ZipError::NothingToDo("no match files".to_string()).into());
    }

    let mut writer = run_state.writer.take().expect("Writer not initialized");
    let mut archive = run_state.archive.take().expect("Archive not initialized");

    let archive_names = archive.file_names();

    for (new_name, new_path) in files_map.iter() {
        let exits_in_archive = archive_names.contains(new_name);
        if exits_in_archive {
            log::debug!("{} already exists in archive, should update?", new_name);
            let file = archive.by_name(new_name)?;
            let should_update = should_update_file(&file, new_path)?;
            if should_update {
                log::info!("{} need update...", new_name);
                run_state.print_operation_start("updating", new_name)?;
                writer.raw_copy_file(&file, new_name.to_string())?;
                run_state.total_original_size += file.origin_size() as u64;
                run_state.total_compressed_size += file.compressed_size() as u64;
                run_state.print_operation_end_args(
                    file.origin_size() as u64,
                    file.compressed_size() as u64,
                    file.compression_method(),
                );
            }
        } else {
            log::debug!("{} not exists in archive, should add", new_name);

            let _ = run_state.print_operation_start("adding", new_name);

            match copy_local_file_to_zip(&mut run_state, &mut writer, new_path, new_name.clone()) {
                Ok(tracker) => {
                    run_state.total_original_size += tracker.original_size;
                    run_state.total_compressed_size += tracker.compressed_size;
                    run_state.changed_files.push(new_name.clone());

                    log::debug!("File {}: Original Size: {}, Compressed Size: {}, Compression Ratio: {:.2}%", new_name, tracker.original_size, tracker.compressed_size, tracker.ratio);
                    run_state.print_operation_end(&tracker);
                }
                Err(e) => {
                    log::warn!("Failed to add file {}: {}", new_name, e);
                    return Err(e);
                }
            }
        }
    }

    run_state.writer = Some(writer);
    run_state.archive = Some(archive);

    // 完成zip文件
    run_state.finish()?;
    run_state.print_summary_verbose();

    Ok(())
}
